/**
 * 判定屏幕上两个像素点的距离是否<distance, map是leaflet的实例
 * @param {L.map} map 地图对象
 * @param {L.point} p1 点1 [lat, lng]
 * @param {L.point} p2 点2 [lat, lng]
 * @param {Number} distance 距离值
 */
export function isNearbyPoint (map, p1, p2, distance = 10) {
    const newP1 = map.latLngToContainerPoint(p1)
    const newP2 = map.latLngToContainerPoint(p2)
    const dx = Math.abs(newP1.x - newP2.x)
    const dy = Math.abs(newP1.y - newP2.y)
    return Math.sqrt(dx * dx + dy * dy) < distance
}

/**
 * 逆转lngLats数组的每一位，将[lng, lat]转[lat, lng]
 * @param {Array<[lng, lat]>} lngLats
 */
export function reverseLnglats (lngLats) {
    return lngLats.map(item => { return [item[1], item[0]] })
}

/**
 * 计算多边形的面积，默认返回亩数
 * @param {Array<[lat, lng]>} latlngs 闭合多边形坐标点数组：[[lat1, lng1], [lat2, lng2]...]
 * @param {Boolean} isAcres 是否转成亩数返回，默认true
 */
export function computeArea (latlngs, isAcres = true) {
    const lngLats = reverseLnglats(latlngs)
    const area = turf.area(turf.polygon([lngLats]))
    return (isAcres ? (area / 666.66666).toFixed(2) : area) - 0
}

// 计算三角形的面积
function computeTriangleArea (p0, p1, p2) {
    let area = 0.0
    area = p0[1] * p1[0] + p1[1] * p2[0] + p2[1] * p0[0] - p1[1] * p0[0] - p2[1] * p1[0] - p0[1] * p2[0]
    return area / 2
}

/**
 * 获取区域的中心点，返回中心点坐标[lat, lng]
 * @param {*} latlngs 闭合多边形坐标点数组：[[lat1, lng1], [lat2, lng2]...]
 */
export function computeRegionCenterPoint (latlngs) {
    if (latlngs.length < 3) {
        return null
    }
    let sumX = 0
    let sumY = 0
    let sumArea = 0
    let p1 = latlngs[1]
    let p2 = null
    let area = 0
    for (let i = 2; i < latlngs.length; i++) {
        p2 = latlngs[i]
        area = computeTriangleArea(latlngs[0], p1, p2)
        sumArea += area
        sumX += (latlngs[0][1] + p1[1] + p2[1]) * area
        sumY += (latlngs[0][0] + p1[0] + p2[0]) * area
        p1 = p2
    }
    const lat = sumY / sumArea / 3
    const lng = sumX / sumArea / 3
    return [lat, lng]
}

/**
 * 求点point到由点P1和点P2构成的直线的最近距离和点的坐标
 * @param {Array<[lat, lng]>} point
 * @param {Array<[lat, lng]>} p1
 * @param {Array<[lat, lng]>} p2
 */
export function computePoint2LinePositionAndDistance (point, p1, p2) {
    const [xx, yy] = point
    const [x1, y1] = p1
    const [x2, y2] = p2
    let ang1 = 0
    let ang2 = 0
    let ang = 0
    let m = 0
    let result = 0
    // 分别计算三条边的长度
    const a = Math.sqrt((x1 - xx) * (x1 - xx) + (y1 - yy) * (y1 - yy))
    if (a === 0) {
        return [0, { x: x1, y: y1 }]
    }
    const b = Math.sqrt((x2 - xx) * (x2 - xx) + (y2 - yy) * (y2 - yy))
    if (b === 0) {
        return [0, { x: x2, y: y2 }]
    }
    const c = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))
    // 如果线段是一个点则退出函数并返回距离
    if (c === 0) {
        result = a
        return [result, { x: x1, y: y1 }]
    }
    // 如果点(xx,yy到点x1,y1)这条边短
    if (a < b) {
        // 如果直线段AB是水平线。得到直线段AB的弧度
        if (y1 === y2) {
            if (x1 < x2) {
                ang1 = 0
            } else {
                ang1 = Math.PI
            }
        } else {
            m = (x2 - x1) / c
            if (m - 1 > 0.00001) {
                m = 1
            }
            ang1 = Math.acos(m)
            if (y1 > y2) {
                ang1 = Math.PI * 2 - ang1
            } // 直线(x1,y1)-(x2,y2)与折X轴正向夹角的弧度
        }
        m = (xx - x1) / a
        if (m - 1 > 0.00001) {
            m = 1
        }
        ang2 = Math.acos(m)
        if (y1 > yy) {
            ang2 = Math.PI * 2 - ang2
        } // 直线(x1,y1)-(xx,yy)与折X轴正向夹角的弧度
        ang = ang2 - ang1
        if (ang < 0) {
            ang = -ang
        }
        if (ang > Math.PI) {
            ang = Math.PI * 2 - ang
        }
        // 如果是钝角则直接返回距离
        if (ang > Math.PI / 2) {
            return [a, { x: x1, y: y1 }]
        }
        // 返回距离并且求得当前距离所在线段的坐标
        if (x1 === x2) {
            return [b * Math.sin(ang), { x: x1, y: yy }]
        } else if (y1 === y2) {
            return [b * Math.sin(ang), { x: xx, y: y1 }]
        }
        // 直线的斜率存在且不为0的情况下
        let x = 0
        let y = 0
        const k1 = ((y2 - y1) / x2 - x1)
        const kk = -1 / k1
        const bb = yy - xx * kk
        const b1 = y2 - x2 * k1
        x = (b1 - bb) / (kk - k1)
        y = kk * x + bb
        return [a * Math.sin(ang), { x, y }]
    }
    // 如果两个点的纵坐标相同，则直接得到直线斜率的弧度
    if (y1 === y2) {
        if (x1 < x2) {
            ang1 = Math.PI
        } else {
            ang1 = 0
        }
    } else {
        m = (x1 - x2) / c
        if (m - 1 > 0.00001) {
            m = 1
        }
        ang1 = Math.acos(m)
        if (y2 > y1) {
            ang1 = Math.PI * 2 - ang1
        }
    }
    m = (xx - x2) / b
    if (m - 1 > 0.00001) {
        m = 1
    }
    ang2 = Math.acos(m) // 直线(x2-x1)-(xx,yy)斜率的弧度
    if (y2 > yy) {
        ang2 = Math.PI * 2 - ang2
    }
    ang = ang2 - ang1
    if (ang < 0) {
        ang = -ang
    }
    if (ang > Math.PI) {
        ang = Math.PI * 2 - ang
    } // 交角的大小
    // 如果是对角则直接返回距离
    if (ang > Math.PI / 2) {
        return [b, { x: x2, y: y2 }]
    }
    // 如果是锐角，返回计算得到的距离,并计算出相应的坐标
    if (x1 === x2) {
        return [b * Math.sin(ang), { x: x1, y: yy }]
    } else if (y1 === y2) {
        return [b * Math.sin(ang), { x: xx, y: y1 }]
    }
    // 直线的斜率存在且不为0的情况下
    let x = 0
    let y = 0
    const k1 = ((y2 - y1) / x2 - x1)
    const kk = -1 / k1
    const bb = yy - xx * kk
    const b1 = y2 - x2 * k1
    x = (b1 - bb) / (kk - k1)
    y = kk * x + bb
    return [b * Math.sin(ang), { x, y }]
}

// 判断两线段在屏幕上是否有交叉
function isSegmentLineCrossed (segA, segB) {
    const abc = (segA[0].x - segB[0].x) * (segA[1].y - segB[0].y) - (segA[0].y - segB[0].y) * (segA[1].x - segB[0].x)
    const abd = (segA[0].x - segB[1].x) * (segA[1].y - segB[1].y) - (segA[0].y - segB[1].y) * (segA[1].x - segB[1].x)
    if (abc * abd >= 0) {
        return false
    }
    const cda = (segB[0].x - segA[0].x) * (segB[1].y - segA[0].y) - (segB[0].y - segA[0].y) * (segB[1].x - segA[0].x)
    const cdb = cda + abc - abd
    return !(cda * cdb >= 0)
}

/**
 * 判定闭合区域是否有线段交叉，返回true或者false
 * @param {L.map} map Map对象
 * @param {Array<[lat, lng]>} latlngs 坐标点数组
 * @returns
 */
export function isCrossedPolygon (map, latlngs) {
    if (latlngs.length <= 3) {
        return false
    }
    let pointA1 = null
    let pointA2 = null
    let pointB1 = null
    let pointB2 = null
    for (let i = 3; i < latlngs.length; i++) {
        pointA1 = latlngs[i]
        pointA2 = latlngs[i - 1]
        for (let j = 1; j <= i - 2; j++) {
            pointB1 = latlngs[j]
            pointB2 = latlngs[j - 1]
            if (isSegmentLineCrossed([map.latLngToContainerPoint(pointA1), map.latLngToContainerPoint(pointA2)], [map.latLngToContainerPoint(pointB1), map.latLngToContainerPoint(pointB2)])) {
                return true
            }
        }
    }
    return false
}
